//----------------------------------------------------------------------------------------------
//	Filename:	EdgeGraph.h
//	Author:		Sandro Spina
//	Date:		27/01/2013
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
#pragma once
#include "UniqueId.h"
#include <map>
#include <stack>
#include <Geometry\Vector3.h>

#include "SegmentsGraph.h"

namespace Illumina
{
	namespace Core
	{		
		struct GraphCut;

		//In this graph states represent edge segments in the pointcloud
		class EdgeGraph
		{
		public:
			::UniqueID * nodeID;

			enum shape {
				line,
				plane,
				sphere,
				complex,
				compound,
				notset
			};

			//More actions can be added here eventually ...
			enum action {
				add_direction,
				transition_count
			};

			enum attributes {
				angle,			//angle between nodes (shapes)
				dot,			//dot product between nodes (shapes)
			};

			enum nodetype {
				accepting,
				rejecting,
				unknown
			};
			
			struct EdgeStats
			{
				std::string label;		
				int strength;		
				float dot;
				float epsilon;
				std::vector<action> actions;
			};

			//Node IDs are the same as corresponding edge segment ids.
			struct NodeStats
			{				 
				std::string label;
				int point_count;
				//int fork_condition; // 0=OR, 1=AND
				shape shape;
				nodetype type;
				Vector3 orientation;
				Vector3 bounding_min;
				Vector3 bounding_max;
				Vector3 mean_bounding_volume;
			};

			struct Node
			{
				int id;	
				int used;
				NodeStats* stats;              
				std::map<int, std::pair<EdgeStats*, Node*> *> * edges;	//Changed from Vector to Map
			};	

			std::map<int, Node*> * nodes;
			std::map<int, Node*>::iterator nodesIterator;

			//std::stack<std::vector<int>*> * ConsumedStates;
	
			Illumina::Core::List<Node*> * DisjointStructureGraphs;

			std::map<std::string, int> * DirectionsTravelled;	

			EdgeGraph(void);

			//Create and populate a new node to represent a surface segment. Add to nodes map.
			void CreateNewNode(SegmentsGraph::SurfaceSegment * &p_ss);

			void AddNodeConnection(SegmentsGraph::SurfaceSegment * &p_segment_source, SegmentsGraph::SurfaceSegment * &p_segment_sink, int p_strength);

			//Returns a list of indices in breadth first order
			Illumina::Core::List<int> * BreadthFirstTraversal(Node * p_initial);
	
			//Graph Search Functions. map<node id, node>
			//std::map<int, std::vector<GraphCut*>*> * SearchSceneGraph(ObjStructureGraph * structure);

			//Merge/Pruning(Deletion) Methods ... small states with adjacent (same type) states, etc.
			void MergeSmallStates(int p_min_number_of_points, SegmentsGraph * p_sg);
			void MergeBigStatesAcrossWeakEdges(int p_min_number_of_points, SegmentsGraph * p_sg);
			void MergeBigStatesAcrossWeakEdges(SegmentsGraph * p_sg);
			void PruneSmallStates(int p_min_number_of_points);
			void PruneBigStates(int p_max_number_of_points);
			void PruneWeakEdges(int p_min_number_of_points);

			//RanSAC Methods over states ... Can be used to merge together or split adjacent states
			bool RanSAC_FitCuboid(std::vector<int> p_states);
			bool RanSAC_FitPlane(std::vector<int> p_states);
			bool RanSAC_FitSphere(std::vector<int> p_states);
			bool RanSAC_FitCylinder(std::vector<int> p_states);
	
			//Shape Structure Graphs Search
			std::vector<std::vector<int>> SearchCuboids();
			std::vector<std::vector<int>> SearchPlanes();
			std::vector<std::vector<int>> SearchSpheres();
			std::vector<std::vector<int>> SearchCylinders();
			std::vector<std::vector<int>> SearchObject(std::string p_shapeName);
	
			//Searches fpr subgraphs (objects) making up the scene
			//std::map<int, std::vector<GraphCut*>*> * SearchSceneGraph(std::string &query);

			//Given two nodes, returns pairs of compatible edges.
			//bool EdgesCompatible(ObjStructureGraph::Node * p_nodeStructure, StructureGraph::Node * p_nodeScene, std::vector<std::pair<int, int>> * &compatible, std::vector<int> * &edgeIndices);

			//Check compatibility between p_edge1 of p_node1 and p_edge2 of p_node2
			//bool EdgeCompatible(ObjStructureGraph::Node * p_nodeStructure, int p_edge1, StructureGraph::Node * p_nodeScene, int p_edge2);
		};
	}
}
		
